package hos.soap;

import org.ksoap2.HeaderProperty;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.kxml2.kdom.Element;
import org.kxml2.kdom.Node;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import hos.http.HttpBaseRequest;
import hos.http.HttpBaseRequestBody;
import hos.http.HttpBaseRequestDownload;
import hos.http.HttpBaseRequestSoap;
import hos.http.HttpFile;
import hos.http.HttpParam;
import hos.http.HttpRequestSoap;
import hos.http.HttpUtils;
import hos.okhttp.http.FileRequestBody;
import okhttp3.FormBody;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;

/**
 * <p>Title: SoapUtils </p>
 * <p>Description:  </p>
 * <p>Company: www.mapuni.com </p>
 *
 * @author : 蔡俊峰
 * @version : 1.0
 * @date : 2024-04-06 20:32
 */
public class SoapUtils {

    public static OkHttpClient buildOkhttp(final OkHttpClient okHttpClient, HttpBaseRequest<?> request) {
        List<Interceptor> interceptors = okHttpClient.interceptors();
        OkHttpClient.Builder builder = okHttpClient.newBuilder()
                .connectTimeout(request.getConnectTimeout(), TimeUnit.SECONDS)
                .readTimeout(request.getReadTimeout(), TimeUnit.SECONDS)
                .writeTimeout(request.getWriteTimeout(), TimeUnit.SECONDS)
                .retryOnConnectionFailure(false);
        boolean isSoapInterceptor = false;
        for (Interceptor interceptor : interceptors) {
            if (interceptor instanceof SoapOkHttpInterceptor) {
                isSoapInterceptor = true;
                break;
            }
        }
        if (!isSoapInterceptor) {
            builder.addInterceptor(new SoapOkHttpInterceptor(request.getRetryCount()));
        }
        return builder.build();
    }

    public static List<HeaderProperty> buildHeader(HttpBaseRequestSoap<?> request) {
        // 请求头部处理
        List<HeaderProperty> headerList = new ArrayList<>();
        Map<String, String> header = request.getHeader();
        if (header != null) {
            Set<String> headerKeys = header.keySet();
            for (String key : headerKeys) {
                HeaderProperty property = new HeaderProperty(key, header.get(key));
                headerList.add(property);
            }
        }
        return headerList;
    }

    public static Element[] buildHeaderOut(HttpBaseRequestSoap<?> request) {
        String nameSpace = request.getNameSpace();
        // SoapHeader在这里
        Map<String, String> headerBody = request.getHeaderBody();
        Element[] headerElement = new Element[1];
        headerElement[0] = new Element().createElement(nameSpace, "SoapHeader");
        Set<String> headerBodyKeys = headerBody.keySet();
        for (String headerBodyKey : headerBodyKeys) {
            Element element = new Element().createElement(nameSpace, headerBodyKey);
            element.addChild(Node.TEXT, headerBody.get(headerBodyKey));
            headerElement[0].addChild(Node.ELEMENT, element);
        }
        return headerElement;
    }

    public static SoapObject buildSoapObject(HttpBaseRequestSoap<?> request) {
        String nameSpace = request.getNameSpace();
        String methodName = request.getMethodName();
        // 设置Soap对象
        SoapObject soapObject = new SoapObject(nameSpace, methodName);
        // 请求头部处理
        List<HttpParam> dataList = request.getData();
        /* 装入参数 */
        if (dataList != null) {
            for (HttpParam data : dataList) {
                soapObject.addProperty(data.getKey(), data.getValue());
            }
        }
        return soapObject;
    }

    public static SoapSerializationEnvelope buildSoapSerializationEnvelope(HttpBaseRequestSoap<?> request) {
        boolean dotNet = request.getDotNet();
        // 设置Soap消息
        final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(((HttpRequestSoap) request).getVersion());
        // 设置是否调用的是dotNet开发的WebService
        envelope.dotNet = dotNet;
        envelope.headerOut = buildHeaderOut(request);
        envelope.setOutputSoapObject(buildSoapObject(request));
        return envelope;
    }


    /**
     * 处理请求体
     *
     * @param request 请求
     */
    public static RequestBody buildRequestBody(HttpBaseRequest<?> request, SoapSerializationEnvelope envelope) {
        List<HttpParam> params = new LinkedList<>();
        List<HttpParam> bodyParameters = request.getBodyParameters();
        if (bodyParameters != null) {
            params.addAll(bodyParameters);
        }
        String type = request.getContentType();
        MediaType contentType = MediaType.parse(type);
        if (request instanceof HttpBaseRequestSoap<?>) {
            HttpBaseRequestSoap<?> requestSoap = (HttpBaseRequestSoap<?>) request;
            try {
                byte[] requestData = envelope.createRequestData();
                return RequestBody.create(requestData, contentType);
            } catch (IOException e) {
                e.printStackTrace();
                return RequestBody.create(requestSoap.getDataXml().getBytes(), contentType);
            }
        }
        if (request instanceof HttpBaseRequestDownload<?>) {
            String bodyString = HttpUtils.urlParam(params);
            return RequestBody.create(bodyString, contentType);
        }
        if (request instanceof HttpBaseRequestBody<?>) {
            HttpBaseRequestBody<?> httpRequestBody = (HttpBaseRequestBody<?>) request;
            Object data = httpRequestBody.getData();
            List<HttpFile> fileList = httpRequestBody.getFileList();
            if (fileList != null && !fileList.isEmpty()) {
                MultipartBody.Builder multipartBuilder = new MultipartBody.Builder();
                multipartBuilder.setType(MultipartBody.FORM);
                // 添加附件
                for (HttpFile httpFile : fileList) {
                    File file = httpFile.getFile();
                    RequestBody fileBody = new FileRequestBody(file);
                    multipartBuilder.addFormDataPart(httpFile.getKey(), httpFile.getFileName(),
                            fileBody);
                }
                // 添加参数
                builderMultipartBody(params, multipartBuilder);
                return multipartBuilder.build();
            }
            if (data != null) {
                if (data instanceof byte[]) {
                    return RequestBody.create((byte[]) data, contentType);
                }
                return RequestBody.create((String) data, contentType);
            }
            boolean isMultipart = httpRequestBody.isMultipart();
            boolean isFormEncoded = httpRequestBody.isFormEncoded();
            if (isFormEncoded) {
                FormBody.Builder formBuilder = new FormBody.Builder();
                builderFormBody(params, formBuilder);
                return formBuilder.build();
            }
            if (isMultipart) {
                MultipartBody.Builder multipartBuilder = new MultipartBody.Builder();
                multipartBuilder.setType(MultipartBody.FORM);
                builderMultipartBody(params, multipartBuilder);
                return multipartBuilder.build();
            }
            String bodyString = HttpUtils.urlParam(params);
            return RequestBody.create(bodyString, contentType);
//            // 添加上传监听
//            if (httpRequestBody.uploadProgressListeners() != null && !httpRequestBody.uploadProgressListeners().isEmpty()) {
//                requestBody = new ProgressRequestBody(httpRequestBody.uploadProgressListeners(), requestBody);
//            }
        }
        // Get
        String bodyString = HttpUtils.urlParam(request.getBodyParameters());
        return RequestBody.create(bodyString, contentType);
    }

    private static void builderFormBody(List<HttpParam> params, FormBody.Builder formBuilder) {
        // 添加参数
        for (HttpParam param : params) {
            String key = param.getKey();
            Object value = param.getValue();
            boolean isEncoded = param.isEncoded();
            if (value == null) {
                formBuilder.add(key, "");
                continue;
            }
            if (value instanceof String) {
                if (((String) value).length() == 0 || "null".equalsIgnoreCase((String) value)) {
                    formBuilder.add(key, "");
                } else {
                    if (isEncoded) {
                        formBuilder.addEncoded(key, String.valueOf(value));
                    } else {
                        formBuilder.add(key, String.valueOf(value));
                    }
                }
            } else {
                formBuilder.add(key, String.valueOf(value));
            }
        }
    }

    private static void builderMultipartBody(List<HttpParam> params, MultipartBody.Builder multipartBuilder) {
        for (HttpParam param : params) {
            String key = param.getKey();
            Object value = param.getValue();
            if (value == null) {
                multipartBuilder.addFormDataPart(key, "");
                continue;
            }
            if (value instanceof String) {
                if (((String) value).length() == 0 || "null".equalsIgnoreCase((String) value)) {
                    multipartBuilder.addFormDataPart(key, "");
                } else {
                    multipartBuilder.addFormDataPart(key, String.valueOf(value));
                }
            } else if (value instanceof byte[]) {
                multipartBuilder.addFormDataPart(key, null,
                        RequestBody.create((byte[]) value, null));
            } else {
                multipartBuilder.addFormDataPart(key, String.valueOf(value));
            }
        }
    }
}
